home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Workspace / AltDock / Source / IconView.m < prev    next >
Text File  |  1995-06-12  |  10KB  |  390 lines

  1.  
  2. /* IconView.m */
  3.  
  4. #import <objc/List.h>
  5. #import <appkit/Bitmap.h>
  6. #import <appkit/Listener.h>
  7. #import <appkit/graphics.h>
  8. #import <dpsclient/psops.h>
  9. #import <dpsclient/wraps.h>
  10. #import <strings.h>
  11. #import <libc.h>
  12. #import <math.h>
  13. #import "MyApp.h"
  14. #import "DockSpeaker.h"
  15. #import "IconView.h"
  16.  
  17. #define UPPER_RIGHT 1
  18. #define LOWER_RIGHT 2
  19.  
  20. @implementation IconView
  21.  
  22. + new:(char *)name :icon :(int)xCoord :(int)yCoord
  23. {
  24.     self = [super new];
  25.     
  26.     /* copy the app's name */
  27.     appName = (char *)malloc(strlen(name) + 1);
  28.     strcpy(appName, name);
  29.     
  30.     /* initialize bitmap locations */
  31.     bitmap = icon;
  32.     activeBitmap = [Bitmap findBitmapFor:"active"];
  33.  
  34.     /* save location in dock grid */
  35.     xGridLocation = xCoord;
  36.     yGridLocation = yCoord;
  37.     
  38.     /* figure out if we're the dock window */
  39.     if (!strcmp(appName, "Dock")) {
  40.       theDock = YES;
  41.       altDocAppHidden = NO;
  42.     }
  43.     
  44.     /* initialize */
  45.     highLighted = NO;
  46.     active = NO;
  47.     appsPSContext = 0;
  48.     
  49.     return self;
  50. }
  51.  
  52. - initialize:list :(int)minX :(int)minY :(int)maxX :(int)maxY
  53. /* give the dock the bounding box and list of all app windows */
  54. {
  55.     xMin = minX;
  56.     xMax = maxX;
  57.     yMin = minY;
  58.     yMax = maxY;
  59.     
  60.     windowList = list;
  61.     
  62.     /* create the drawing order lists for moving diagonally */
  63.     upperRight = [self createOrderedListForCorner:UPPER_RIGHT];
  64.     lowerRight = [self createOrderedListForCorner:LOWER_RIGHT];
  65.         
  66.     return self;
  67. }
  68.  
  69. - createOrderedListForCorner:(int)corner
  70. /* returns a list of windows ordered based on the corner parameter     */
  71. /* (this is the order in which they should be moved when moving toward  */
  72. /* this corner                                */
  73. {
  74.     int    i, x1, y1, x2, y2, j;
  75.     id     list, tempList, iconWindow;
  76.     
  77.     list = [List new];
  78.     tempList = [List new];   
  79.     i = [windowList count];
  80.     
  81.     /* insert all windows into the temporary list (ordered by x position) */
  82.     while (i--) {
  83.       iconWindow = [windowList objectAt:i];
  84.       [[iconWindow contentView] coordinates:&x1 :&y1];
  85.       
  86.       j = 0;
  87.       while (j < [tempList count]) {
  88.         [[[tempList objectAt:j] contentView] coordinates:&x2 :&y2];
  89.     
  90.     /* sort by x position */
  91.     if (corner == UPPER_RIGHT && x1 >= x2) {
  92.       break;
  93.     } else if (x1 >= x2) {
  94.       break;
  95.     }
  96.     j++;
  97.       }
  98.       if (j == [tempList count]) {
  99.         [tempList addObject:iconWindow];
  100.       } else if (![tempList insertObject:iconWindow at:j]) {
  101.         [tempList addObject:iconWindow];
  102.       }
  103.     }
  104.  
  105.     i = [tempList count];
  106.     
  107.     /* insert tempList windows into the final list, sorted by x and y */
  108.     while (i--) {
  109.       iconWindow = [tempList objectAt:i];
  110.       [[iconWindow contentView] coordinates:&x1 :&y1];
  111.       
  112.       j = 0;
  113.       while (j < [list count]) {
  114.         [[[list objectAt:j] contentView] coordinates:&x2 :&y2];
  115.     
  116.     /* sort by y */
  117.     if (corner == UPPER_RIGHT && x1 >= x2 && y1 >= y2) {
  118.       break;
  119.     } else if (x1 >= x2 && y1 <= y2) {
  120.       break;
  121.     }
  122.     j++;
  123.       }
  124.       if (j == [list count]) {
  125.         [list addObject:iconWindow];
  126.       } else if (![list insertObject:iconWindow at:j]) {
  127.         [list addObject:iconWindow];
  128.       }
  129.     }
  130.  
  131.     [tempList free];
  132.     
  133.     return list;
  134. }
  135.  
  136. - drawSelf:(const NXRect *)rects :(int)rectCount
  137. {
  138.     NXRect   drawRect;
  139.     int      numBitmaps;
  140.     NXPoint  origin, activePoint;
  141.     
  142.     /* initialize a drawing rectangle */
  143.     drawRect.origin.x = drawRect.origin.y = 0.0;
  144.     drawRect.size.width = drawRect.size.height = 64.0;
  145.     origin.x = origin.y = 8.0;
  146.     
  147.     if (!theDock) {
  148.       /* if we're not the dock, draw our bezel */
  149.       NXDrawButton(&drawRect, 0);
  150.       NXInsetRect(&drawRect, 1.0, 1.0);
  151.       NXDrawButton(&drawRect, 0);
  152.       NXInsetRect(&drawRect, -1.0, -1.0);
  153.     
  154.       /* draw our 48x48-bit icon */
  155.       [bitmap composite:NX_SOVER toPoint:&origin];
  156.       activePoint.x = 64.0 - 2.0 - 18.0;
  157.       activePoint.y = drawRect.origin.y + 4.0;
  158.     
  159.       /* draw the three dots if our program isn't active */
  160.       if (!active) {
  161.         [activeBitmap composite:NX_COPY toPoint:&activePoint];
  162.       }
  163.       
  164.       /* highlight ourself if we're getting our app to run or unhide */
  165.       if (highLighted) {
  166.         NXInsetRect(&drawRect, 2.0, 2.0);
  167.         NXHighlightRect(&drawRect);
  168.       }
  169.     } else {
  170.       /* we're the dock so just copy our 64x64-bit icon into ourself */
  171.       origin.x = origin.y = 0.0;
  172.       [bitmap composite:NX_COPY toPoint:&origin];
  173.     }
  174.          
  175.     return self;
  176. }    
  177.  
  178. #define MOVEMASK (NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK)
  179. - mouseDown:(NXEvent *)theEvent
  180. {
  181.     NXPoint    mouseDownLocation;
  182.     NXEvent    *currentEvent;
  183.     NXCoord    oldX, oldY, newX, newY, dx, dy, x, y;
  184.     NXRect     frameRect;
  185.     int        windowNum;
  186.     
  187.     /* if we're not the dock, see if we should unhide our application */
  188.     if (!theDock) {
  189.       [self handleNonDock:theEvent];
  190.       return self;
  191.     }
  192.     
  193.     /* hide or unhide the dock's menus and icon window if a double click */
  194.     if (theEvent->data.mouse.click == 2) {
  195.       [self hideOrUnhide];
  196.     }
  197.     
  198.     [window addToEventMask:MOVEMASK];
  199.     
  200.     /* get the dock window's location */
  201.     [window getFrame:&frameRect];
  202.  
  203.     /* convert the mouse's location to global (screen) coordinates */
  204.     mouseDownLocation = theEvent->location;
  205.     PScurrenttoscreen(mouseDownLocation.x, mouseDownLocation.y, &oldX, &oldY);
  206.     
  207.     /* initialization */
  208.     newX = frameRect.origin.x;
  209.     newY = frameRect.origin.y;
  210.     
  211.     currentEvent = [NXApp getNextEvent:MOVEMASK];
  212.     
  213.     while (currentEvent->type != NX_MOUSEUP) {
  214.       /* things get messed up if we move our window and ask the window */
  215.       /* to convert our mouse location to screen coordinates, so we    */
  216.       /* use this call instead to get the mouse's screen location      */
  217.       PScurrentmouse(0, &x, &y);
  218.       
  219.       /* offset from previous mouse location */
  220.       dx = x - oldX;
  221.       dy = y - oldY;
  222.       
  223.       /* compute the dock window's proposed origin */
  224.       newX = dx + frameRect.origin.x;
  225.       newY = dy + frameRect.origin.y;
  226.       
  227.       /* make sure this is ok (and fix it if not) */
  228.       [self checkCoords:&newX :&newY];
  229.       
  230.       /* move everyone the correct amount */ 
  231.       [self moveWindows:(newX - frameRect.origin.x)
  232.                      :(newY - frameRect.origin.y)];
  233.       
  234.       /* get our new origin and save the current mouse location */
  235.       [window getFrame:&frameRect];
  236.       oldX = x;
  237.       oldY = y;
  238.       
  239.       /* wait for another mouse event */
  240.       currentEvent = [NXApp getNextEvent:MOVEMASK];
  241.     }
  242.     
  243.     /* impose the NeXT dock's grid behaviour on the window positions */
  244.     [self snapToGrid:&newX :&newY];
  245.     [self moveWindows:(newX - frameRect.origin.x)
  246.                  :(newY - frameRect.origin.y)];
  247.     
  248.     return self;
  249. }
  250.  
  251. - checkCoords:(float *)x :(float *)y
  252. /* constrain the dock window's location based on the bounding box */
  253. {
  254.     float    maxX, maxY;
  255.     
  256.     if (*x < 4) *x = 4;
  257.     if (*y < 0) *y = 0;
  258.     
  259.     maxX = (xMax - xMin) * 64.0 + 4.0;
  260.     maxY = (yMax - yMin) * 64.0;
  261.     
  262.     if (*y > maxY) *y = maxY;
  263.     
  264.     if (*x > maxX) *x = maxX;
  265.     
  266.     return self;
  267. }
  268.  
  269. - snapToGrid:(float *)x :(float *)y
  270. /* make sure windows lay on 64-bit boundaries */
  271. {
  272.     *x = rint((*x - 4) / 64.0) * 64.0 + 4.0;
  273.     *y = rint(*y / 64.0) * 64.0;
  274.     return self;
  275. }
  276.  
  277. - moveWindows:(float)dx :(float)dy
  278. /* move the windows dx and dy */
  279. {
  280.     int     numberOfWindows, startX, stopX, startY, stopY, i;
  281.     id      theList, moveWindow;
  282.     NXRect  frameRect;
  283.     BOOL    reverse;
  284.     
  285.     /* note that when moving to upper left, we can use the lower right  */
  286.     /* window list, just traverse it in the opposite direction        */
  287.     if (dx <= 0 && dy < 0) {
  288.       theList = upperRight;
  289.       reverse = YES;
  290.     } else if (dx >= 0 && dy > 0) {
  291.       theList = upperRight;
  292.       reverse = NO;
  293.     } else if (dx < 0 && dy >= 0) {
  294.       theList = lowerRight;
  295.       reverse = YES;
  296.     } else {    /* (dx > 0 && dy <= 0) */
  297.       theList = lowerRight;
  298.       reverse = NO;
  299.     }
  300.         
  301.     numberOfWindows = [theList count];
  302.     
  303.     if (!reverse) {
  304.       i = 0;
  305.       while (i < numberOfWindows) {
  306.     moveWindow = [theList objectAt:i++];
  307.     [moveWindow getFrame:&frameRect];
  308.     [moveWindow moveTo:(frameRect.origin.x + dx)
  309.               :(frameRect.origin.y + dy)];
  310.       }
  311.     } else {
  312.       i = numberOfWindows;
  313.       while (i--) {
  314.     moveWindow = [theList objectAt:i];
  315.     [moveWindow getFrame:&frameRect];
  316.     [moveWindow moveTo:(frameRect.origin.x + dx)
  317.               :(frameRect.origin.y + dy)];
  318.       }
  319.     }
  320.     
  321.     return self;
  322. }
  323.  
  324. - handleNonDock:(NXEvent *)theEvent
  325. /* click in a non-dock window */
  326. {
  327.     port_t  appPort;
  328.     int     flag;
  329.     
  330.     /* only concern ourselves with double clicks */
  331.     if (theEvent->data.mouse.click == 2) {
  332.       /* simulate NeXT dock functionality */
  333.       highLighted = YES;
  334.       [self display];
  335.       [NXApp deactivateSelf];
  336.       
  337.       /* get the WorkSpace to make sure our app is running */
  338.       appPort = NXPortFromName((rindex(appName, '/') + 1), NULL);
  339.       if (appPort == PORT_NULL) {
  340.           /* something went wrong */
  341.         highLighted = NO;
  342.     [self display];
  343.         [NXApp activateSelf:YES];
  344.         return self;
  345.       }
  346.       /* now unhide the app (just like the WorkSpace) */
  347.       [[NXApp appSpeaker] setSendPort:appPort];
  348.       [[NXApp appSpeaker] unhide];
  349.       
  350.       /* save our app's PostScript context (for a later version, maybe) */
  351.       appsPSContext = [NXApp activeApp];
  352.       
  353.       /* all done, so show app is active and unhighlight ourselves */
  354.       highLighted = NO;
  355.       active = YES;
  356.       [self display];
  357.     }
  358.     
  359.     return self;
  360. }
  361.  
  362. - hideOrUnhide
  363. /* hide or unhide the dock app's menu */
  364. {
  365.     if (altDocAppHidden) {
  366.       [[NXApp mainMenu] orderFront:self];
  367.       altDocAppHidden = NO;
  368.     } else {
  369.       [[NXApp mainMenu] orderOut:self];
  370.       altDocAppHidden = YES;
  371.     }      
  372.     
  373.     return self;
  374. }
  375.  
  376. - (BOOL)theDock
  377. {
  378.     return theDock;
  379. }
  380.  
  381. - coordinates:(int *)xCoord :(int *)yCoord
  382. /* return our grid coordinates */
  383. {
  384.     *xCoord = xGridLocation;
  385.     *yCoord = yGridLocation;
  386.     return self;
  387. }
  388.  
  389. @end
  390.